/*
 *    Copyright (c) 2018-2025, boss All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * Neither the name of the boss developer nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * Author: boss
 */
package com.hopes.bizz.enforcement.integral.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hopes.bizz.enforcement.common.constant.FlowConstant;
import com.hopes.bizz.enforcement.common.constant.IntegralDicConstant;
import com.hopes.bizz.enforcement.integral.bo.RiskIntegralExchangeAuditBo;
import com.hopes.bizz.enforcement.integral.dto.RiskIntegralExchangeAuditDTO;
import com.hopes.bizz.enforcement.integral.dto.RiskIntegralExchangeDTO;
import com.hopes.bizz.enforcement.integral.entity.RiskIntegralExchangeAuditRecordEntity;
import com.hopes.bizz.enforcement.integral.entity.RiskIntegralExchangeEntity;
import com.hopes.bizz.enforcement.integral.entity.HazIntegralGoodsEntity;
import com.hopes.bizz.enforcement.integral.entity.RiskIntegralStatisticalEntity;
import com.hopes.bizz.enforcement.integral.mapper.RiskIntegralExchangeMapper;
import com.hopes.bizz.enforcement.integral.service.RiskIntegralExchangeAuditRecordService;
import com.hopes.bizz.enforcement.integral.service.RiskIntegralExchangeService;
import com.hopes.bizz.enforcement.integral.service.EnfIntegralGoodsService;
import com.hopes.bizz.enforcement.integral.service.RiskIntegralStatisticalService;
import com.hopes.bizz.enforcement.integral.vo.RiskIntegralExchangeVO;
import com.hopes.boss.act.base.FlowServiceImpl;
import com.hopes.boss.act.base.TaskExecute;
import com.hopes.boss.act.constant.FlowNodeJumpType;
import com.hopes.boss.act.enums.FlowTaskHandlerType;
import com.hopes.boss.act.vo.FlowTaskInfo;
import com.hopes.boss.common.core.exception.BizException;
import com.hopes.boss.common.security.util.SecurityUtils;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 兑换记录
 *
 * @author daijie
 * @date 2023-07-26 11:07:08
 */
@Service
@Slf4j
public class RiskIntegralExchangeServiceImpl extends FlowServiceImpl<RiskIntegralExchangeMapper, RiskIntegralExchangeEntity> implements RiskIntegralExchangeService {

    @Resource
    private RiskIntegralExchangeAuditRecordService riskIntegralExchangeAuditRecordService;

    @Lazy
    @Resource
    private EnfIntegralGoodsService enfIntegralGoodsService;

    @Lazy
    @Resource
    private RiskIntegralStatisticalService riskIntegralStatisticalService;

    @Override
    public Page<RiskIntegralExchangeVO> listPage(Page<RiskIntegralExchangeEntity> page, RiskIntegralExchangeDTO integralExchangeDTO) {
        final LambdaQueryWrapper<RiskIntegralExchangeEntity> queryWrapper = Wrappers.<RiskIntegralExchangeEntity>lambdaQuery()
                .ge(Objects.nonNull(integralExchangeDTO.getBeginTime()), RiskIntegralExchangeEntity::getExchangeTime, integralExchangeDTO.getBeginTime())
                .le(Objects.nonNull(integralExchangeDTO.getEndTime()), RiskIntegralExchangeEntity::getExchangeTime, integralExchangeDTO.getEndTime())
                .eq(Objects.nonNull(integralExchangeDTO.getIssueStatus()), RiskIntegralExchangeEntity::getIssueStatus, integralExchangeDTO.getIssueStatus())
                .eq(Objects.nonNull(integralExchangeDTO.getAuditStatus()), RiskIntegralExchangeEntity::getAuditStatus, integralExchangeDTO.getAuditStatus())
                .eq(Objects.nonNull(integralExchangeDTO.getAuditResult()), RiskIntegralExchangeEntity::getAuditResult, integralExchangeDTO.getAuditResult())
                .eq(Objects.nonNull(integralExchangeDTO.getConfirmStatus()), RiskIntegralExchangeEntity::getConfirmStatus, integralExchangeDTO.getConfirmStatus())
                .orderByDesc(RiskIntegralExchangeEntity::getExchangeTime);
        final Page<RiskIntegralExchangeEntity> selectPage = this.page(page, queryWrapper);
        final List<RiskIntegralExchangeVO> collect = selectPage.getRecords().parallelStream().map(item -> {
            final RiskIntegralExchangeVO integralExchangeVO = new RiskIntegralExchangeVO();
            BeanUtils.copyProperties(item, integralExchangeVO);
            return integralExchangeVO;
        }).collect(Collectors.toList());
        // 构建 vo page 对象
        final Page<RiskIntegralExchangeVO> res = new Page<>(page.getCurrent(), page.getSize(), selectPage.getTotal());
        res.setRecords(collect);
        return res;
    }


    @Override
    public Page<RiskIntegralExchangeVO> listMyPage(Page<RiskIntegralExchangeEntity> page, RiskIntegralExchangeDTO integralExchangeDTO) {
        final LambdaQueryWrapper<RiskIntegralExchangeEntity> queryWrapper = Wrappers.<RiskIntegralExchangeEntity>lambdaQuery()
                .ge(Objects.nonNull(integralExchangeDTO.getBeginTime()), RiskIntegralExchangeEntity::getExchangeTime, integralExchangeDTO.getBeginTime())
                .le(Objects.nonNull(integralExchangeDTO.getEndTime()), RiskIntegralExchangeEntity::getExchangeTime, integralExchangeDTO.getEndTime())
                .eq(RiskIntegralExchangeEntity::getAccountId, SecurityUtils.getUser().getId())
                .eq(Objects.nonNull(integralExchangeDTO.getIssueStatus()), RiskIntegralExchangeEntity::getIssueStatus, integralExchangeDTO.getIssueStatus())
                .eq(Objects.nonNull(integralExchangeDTO.getAuditStatus()), RiskIntegralExchangeEntity::getAuditStatus, integralExchangeDTO.getAuditStatus())
                .eq(Objects.nonNull(integralExchangeDTO.getAuditResult()), RiskIntegralExchangeEntity::getAuditResult, integralExchangeDTO.getAuditResult())
                .eq(Objects.nonNull(integralExchangeDTO.getConfirmStatus()), RiskIntegralExchangeEntity::getConfirmStatus, integralExchangeDTO.getConfirmStatus())
                .orderByDesc(RiskIntegralExchangeEntity::getExchangeTime);
        final Page<RiskIntegralExchangeEntity> selectPage = this.page(page, queryWrapper);
        final List<RiskIntegralExchangeVO> collect = selectPage.getRecords().parallelStream().map(item -> {
            final RiskIntegralExchangeVO integralExchangeVO = new RiskIntegralExchangeVO();
            BeanUtils.copyProperties(item, integralExchangeVO);
            return integralExchangeVO;
        }).collect(Collectors.toList());
        // 构建 vo page 对象
        final Page<RiskIntegralExchangeVO> res = new Page<>(page.getCurrent(), page.getSize(), selectPage.getTotal());
        res.setRecords(collect);
        return res;
    }

    @Override
    public RiskIntegralExchangeVO getById(Long id) {
        final RiskIntegralExchangeEntity riskIntegralExchangeEntity = baseMapper.selectById(id);
        final RiskIntegralExchangeVO riskIntegralExchangeVO = new RiskIntegralExchangeVO();
        QueryWrapper<RiskIntegralExchangeAuditRecordEntity> auditRecordEntityQueryWrapper = new QueryWrapper<>();
        auditRecordEntityQueryWrapper.eq("exchange_id", id);
        auditRecordEntityQueryWrapper.isNotNull("opinion");
        List<RiskIntegralExchangeAuditRecordEntity> list = riskIntegralExchangeAuditRecordService.list(auditRecordEntityQueryWrapper);
        if (!list.isEmpty()) {
            riskIntegralExchangeVO.setOpinion(list.get(0).getOpinion());
        }
        BeanUtils.copyProperties(riskIntegralExchangeEntity, riskIntegralExchangeVO);
        return riskIntegralExchangeVO;
    }

    @Override
    @GlobalTransactional
    @Transactional(rollbackFor = Exception.class)
    public void submit(Long id) {
        // 提交工作流
        RiskIntegralExchangeAuditBo riskIntegralExchangeAuditBo = new RiskIntegralExchangeAuditBo();
        riskIntegralExchangeAuditBo.setId(id);
        TaskExecute taskExecute = new TaskExecute.Build()
                .setBusinessKey(id)
                .setFlowTaskHandlerType(FlowTaskHandlerType.TASK_HANDLE_TYPE_SUBMIT)
                .setBusinessData(riskIntegralExchangeAuditBo)
                .build();
        executeTask(taskExecute);
    }

    @Override
    @GlobalTransactional
    @Transactional(rollbackFor = Exception.class)
    public void handlerAudit(RiskIntegralExchangeAuditDTO riskIntegralExchangeAuditDTO) {
        Integer conclusion = riskIntegralExchangeAuditDTO.getConclusion();
        Long id = riskIntegralExchangeAuditDTO.getId();
        RiskIntegralExchangeAuditBo riskIntegralExchangeAuditBo = new RiskIntegralExchangeAuditBo();
        BeanUtils.copyProperties(riskIntegralExchangeAuditDTO, riskIntegralExchangeAuditBo);
        TaskExecute.Build build = new TaskExecute.Build()
                .setBusinessKey(id)
                .setBusinessData(riskIntegralExchangeAuditBo);
        if (IntegralDicConstant.INTEGRAL_GOODS_AUDIT_RESULT_PASS.equals(conclusion)) {
            // 审核通过，则进行下一步流程
            build.setFlowTaskHandlerType(FlowTaskHandlerType.TASK_HANDLE_TYPE_PASS);
        } else {
            // 审核不通过直接跳转结束节点,处理结束
            build.setFlowTaskHandlerType(FlowTaskHandlerType.TASK_HANDLE_TYPE_JUMP)
                    .setJumpType(FlowNodeJumpType.CUSTOM)
                    .setJumpNode(IntegralDicConstant.INTEGRAL_GOODS_AUDIT_STATUS_END.toString());
        }
        executeTask(build.build());
    }

    @Override
    public void deleteBusiness(Collection<Long> ids) {
        riskIntegralExchangeAuditRecordService.deleteByExchangeIdList(ids);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void doCompletedTask(FlowTaskInfo flowTaskInfo, Long id, FlowTaskHandlerType flowTaskHandlerType, Object data) {
        RiskIntegralExchangeAuditBo riskIntegralExchangeAuditBo = (RiskIntegralExchangeAuditBo) data;
        // 保存审批记录
        RiskIntegralExchangeVO integralExchange = getById(id);
        Long curUser = SecurityUtils.getUserId();
        if (FlowTaskHandlerType.TASK_HANDLE_TYPE_SUBMIT.equals(flowTaskHandlerType)) {
            // 提交创建新记录
            RiskIntegralExchangeAuditRecordEntity record = new RiskIntegralExchangeAuditRecordEntity();
            record.setExchangeId(id);
            record.setStepsName(integralExchange.getAuditStatus());
            record.setHandleTime(new Date());
            record.setHandleUser(curUser);
            riskIntegralExchangeAuditRecordService.save(record);
        } else {
            //  更新
            RiskIntegralExchangeAuditRecordEntity lastRecord = riskIntegralExchangeAuditRecordService.lambdaQuery()
                    .eq(RiskIntegralExchangeAuditRecordEntity::getStepsName, integralExchange.getAuditStatus())
                    .eq(RiskIntegralExchangeAuditRecordEntity::getExchangeId, id)
                    .select(RiskIntegralExchangeAuditRecordEntity::getId)
                    .orderByDesc(RiskIntegralExchangeAuditRecordEntity::getCreateTime)
                    .last("limit 1")
                    .one();
            if (Objects.isNull(lastRecord)) {
                throw new BizException("审批记录不存在!");
            }
            riskIntegralExchangeAuditRecordService.lambdaUpdate()
                    .set(RiskIntegralExchangeAuditRecordEntity::getHandleUser, curUser)
                    .set(RiskIntegralExchangeAuditRecordEntity::getHandleTime, new Date())
                    .set(RiskIntegralExchangeAuditRecordEntity::getConclusion, riskIntegralExchangeAuditBo.getConclusion())
                    .set(RiskIntegralExchangeAuditRecordEntity::getOpinion, riskIntegralExchangeAuditBo.getOpinion())
                    .eq(RiskIntegralExchangeAuditRecordEntity::getId, lastRecord.getId())
                    .update();

            if (IntegralDicConstant.INTEGRAL_GOODS_AUDIT_RESULT_NOT_PASS.equals(riskIntegralExchangeAuditBo.getConclusion())) {
                //审核不通过，退回商品数量
                Integer amount = integralExchange.getAmount();
                HazIntegralGoodsEntity integralGoods = enfIntegralGoodsService.getById(integralExchange.getGoodsId());
                int quantityNumber = Optional.ofNullable(integralGoods.getQuantityNumber()).orElse(0) + amount;
                enfIntegralGoodsService.lambdaUpdate()
                        .set(HazIntegralGoodsEntity::getQuantityNumber, quantityNumber)
                        .eq(HazIntegralGoodsEntity::getId, integralExchange.getGoodsId())
                        .update();
                // 退回积分
                Integer exchangeIntegral = integralGoods.getExchangeIntegral();
                RiskIntegralStatisticalEntity riskIntegralStatistical = riskIntegralStatisticalService.lambdaQuery()
                        .eq(RiskIntegralStatisticalEntity::getAccountId, integralExchange.getAccountId())
                        .one();
                Integer oldIntegral = riskIntegralStatistical.getExchangeableIntegral();
                Integer newIntegral = oldIntegral + exchangeIntegral * amount;
                riskIntegralStatisticalService.lambdaUpdate()
                        .set(RiskIntegralStatisticalEntity::getExchangeableIntegral, newIntegral)
                        .eq(RiskIntegralStatisticalEntity::getAccountId, integralExchange.getAccountId())
                        .update();
            }
        }
        // 保存下一条记录
        RiskIntegralExchangeAuditRecordEntity nextRecord = new RiskIntegralExchangeAuditRecordEntity();
        nextRecord.setExchangeId(id);
        nextRecord.setStepsName(flowTaskInfo.getStatus());
        nextRecord.setExecutorIds(flowTaskInfo.getCandidateStr());
        riskIntegralExchangeAuditRecordService.save(nextRecord);
        // 更新状态
        lambdaUpdate()
                .set(RiskIntegralExchangeEntity::getAuditStatus, flowTaskInfo.getStatus())
                .set(RiskIntegralExchangeEntity::getAuditResult, riskIntegralExchangeAuditBo.getConclusion())
                .eq(RiskIntegralExchangeEntity::getId, id)
                .update();
    }

    @Override
    public String getFlowDefinitionKey(Long id) {
        return FlowConstant.HIDDEN_INTEGRAL_EXCHANGE;
    }
}
